<?php if (! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * 用户验证服务
 */
class User_auth_service extends MY_Service {

    public function __construct() {
        $this->load->library('form_validation'); //表单验证类
        $this->load->model('user_model'); //用户模型

        log_message('debug', 'User_auth_service Class Initialized');
    }

    /**
     * 是否已经登陆
     *
     * @return int 用户UID
     */
    public function is_login() {
        static $login_uid;
        if (isset($login_uid)) return $login_uid;

        if ($ci_loginuser = $this->input->cookie('ci_loginuser')) {
            $this->load->library('encrypt'); //加解密类库
            $ci_loginuser = explode("\t", $this->encrypt->decode($ci_loginuser));
            if (count($ci_loginuser) == 2) {
                list($uid, $hash_password) = $ci_loginuser;
                if (is_numeric($uid)) $login_uid = $uid;
            }
        } else {
            $login_uid = 0;
            $hash_password = '';
        }

        return $login_uid;
    }

    /**
     * 用户登录
     *
     * @param string $identity 用户登录的帐号
     * @param string $password 用户登录的密码
     * @param string $remember 是否记住用户
     * @param string $safe_question 安全问题
     * @param string $safe_answer 安全问题答案
     * @return boolean|int
     */
    public function login($identity, $password, $remember = false, $safe_question = null, $safe_answer = '') {
        if (empty($identity) || empty($password)) {
            $this->set_error('账号或密码不能为空');
            return false;
        }

        //获取登陆用户信息
        $user = $this->get_user_by_loginway($identity);

        //如果在锁定时间内
        if ($this->is_time_locked_out($identity)) {
            $this->set_error('尝试登陆超时限制次数 稍后尝试');
            return false;
        }

        //如果密码相等
        if ($user && $this->check_password($password, $user)) {
            //如果用户还没有激活(验证)
            if ($user['status'] == 0) {
                $this->set_error('用户还未激活');
                return false;
            }
            //记录sessions
            $this->set_login_cookie($user, $remember);
            //更新登陆记录
            $this->update_last_login($user);
            //清除失败登陆次数
            $this->clear_login_attempt($identity);

            $this->set_message('登陆成功');
            return true;
        } else {
            $this->increase_login_attempt($identity);
            $this->set_error('用户账号或密码错误');
            return false;
        }
    }

    /**
     * 用户退出
     */
    public function logout() {
        $this->input->set_cookie('ci_loginuser');
        $this->set_message('退出成功');
        return true;
    }

    /**
     * 获取登陆用户信息
     * 登陆方式: uid, username, email, mobile
     *
     * @param string $identity 用户登录的帐号
     * @return array
     */
    public function get_user_by_loginway($identity) {
        //手机号码登录
        if ($this->form_validation->is_mobilephone($identity)) {
            //TODO
            return array();
        }
        //UID登录
        if (is_numeric($identity)) {
            return $this->user_model->get_by('uid', $identity);
        }
        //email登录
        if ($this->form_validation->valid_email($identity)) {
            return $this->user_model->get_by('email', $identity);
        }
        //用户名登录
        return $this->user_model->get_by('username', $identity);
    }

    /**
     * 更新登陆记录
     *
     * @param array $user
     * @return boolean
     */
    public function update_last_login($user) {
        $save = array('last_login_time' => TIMESTAMP, 'last_login_ip' => $this->input->ip_address());
        $this->db->update('user_data', $save, array('uid' => $user['uid']));
        return $this->db->affected_rows() == 1;
    }

    /**
     * 设置用户登陆标识
     *
     * @param array $user
     * @param string $remember 是否记住用户
     * @return bool
     */
    public function set_login_cookie($user, $remember) {
        $str = $user['uid'] . "\t" . $this->hash_password($user['password'], $user['salt']);
        $this->load->library('encrypt'); //加解密类库
        $str = $this->encrypt->encode($str);
        $this->input->set_cookie('ci_loginuser', $str, $remember ? 86400 * 365 : 0);
        return true;
    }

    /**
     * 检查密码是否正确
     *
     * @param string $password 用户登录的密码
     * @param string $user 用户数据
     * @return boolean
     */
    public function check_password($password, $user) {
        return $this->hash_password($password, $user['salt']) === $user['password'];
    }

    /**
     * 加密密码
     *
     * @param string $password 用户登录的密码
     * @param string $salt 盐值
     * @return string
     */
    public function hash_password($password, $salt = '') {
        return md5($salt . md5($password) . $salt);
    }

    /**
     * 是否在锁定时间内
     *
     * @param string $identity 用户登录的帐号
     * @return bool
     */
    public function is_time_locked_out($identity) {
        $lockout_time = 60;
        return $this->is_max_login_attempt_exceeded($identity) && $this->get_last_attempt_time($identity) > TIMESTAMP - $lockout_time;
    }

    /**
     * 是否超过了最大尝试登陆次数
     *
     * @param string $identity
     * @return boolean
     **/
    public function is_max_login_attempt_exceeded($identity) {
        $max_attempt = 6;
        if ($max_attempt > 0) {
            $current_attempt = $this->get_attempt_num($identity);
            return $current_attempt >= $max_attempt;
        }
        return false;
    }

    /**
     * 获取当前尝试登陆次数
     *
     * @param	string $identity
     * @return	int
     */
    function get_attempt_num($identity) {
        $this->db->select('1', false);
        $this->db->where('ip_address', $this->input->ip_address());
        $query = $this->db->get('user_login_attempt');
        return $query->num_rows();
    }

    /**
     * 获取最后一次尝试登陆时间
     *
     * @param	string $identity
     * @return	int
     */
    public function get_last_attempt_time($identity) {
        $this->db->select_max('login_time');
        $this->db->where('ip_address', $this->input->ip_address());
        $query = $this->db->get('user_login_attempt', 1);
        if ($query->num_rows() > 0) {
            return $query->row()->login_time;
        }
        return 0;
    }

    /**
     * 增加尝试登陆记录
     *
     * @param string $identity 用户登录的帐号
     * @return bool
     */
    public function increase_login_attempt($identity) {
        $save = array();
        $save['ip_address'] = $this->input->ip_address();
        $save['login'] = $identity;
        $save['login_time'] = TIMESTAMP;
        return $this->db->insert('user_login_attempt', $save);
    }

    /**
     * 清除登陆尝试记录
     * 登陆成功后清除登陆记录 并 清除过期后的记录
     *
     * @param string $identity 登陆账号
     * @param int $expiration_time 过期时间
     * @return bool
     */
    public function clear_login_attempt($identity, $expiration_time = 86400) {
        $this->db->where(array('ip_address' => $this->input->ip_address(), 'login' => $identity));
        $this->db->or_where('login_time < ', TIMESTAMP - $expiration_time, false);
        return $this->db->delete('user_login_attempt');
    }

    /**
     * 用户注册
     *
     * @param string $username 用户名称
     * @param string $password 用户密码
     * @param string $email 用户邮箱
     * @param array $additional_data 附加数据
     * @return int $uid
     */
    public function register($username, $password, $email, $additional_data = array(), $groups = array()) {
        //开启邮箱激活
        $email_activation = 1;

        //默认用户组（未验证用户组）
        $default_group = 7;

        //检测同IP多少时间内只能注册一次
        if ($this->is_limit_register()) {
			$this->set_error('同一个IP在24小时内不能被重复注册');
            return false;
		}

        //用户名是否存在
        if ($this->is_username_exist($username)) {
            $this->set_error('用户名已存在');
            return false;
        }
        //Email是否存在
        elseif ($this->is_email_exist($email)) {
            $this->set_error('邮箱已存在');
            return false;
        }
        //如果默认用户组没有设置
        elseif (! $default_group && empty($groups)) {
            $this->set_error('尚未设定默认群组');
            return false;
        }

        //用户数据入库
        $save = array();
        $save['username'] = $username;
        $save['salt'] = $this->salt();
        $save['password'] = $this->hash_password($password, $save['salt']);
        $save['email'] = $email;
        $save['gid'] = $email_activation ? $default_group : 8;
        $this->db->insert('user', $save);
        $uid = $this->db->insert_id();

        //是否邮箱激活
        //TODO: 待完善
        if ($email_activation) {
            $data = array();
            $data['identity'] = '';
            $data['uid'] = '';
            $data['email'] = '';
            $data['activation_code'] = '';
            //$message = $this->load->view('email_activation_templates', $data, true);

            $this->load->library('email');
            $this->email->clear();
            $this->email->from('admin@admin.com', '网站标题');
            $this->email->to('52371354@qq.com');
            $this->email->subject('网站标题 - 帐号激活');
            $this->email->message('激活内容');
            if ($this->email->send() == true) {
                $this->set_message('激活邮件已发送到用户的电子邮箱');
                return $uid;
            } else {
                $this->set_error('激活邮件发送失败');
                return false;
            }
        }

        return (isset($uid)) ? $uid : false;
    }

    /**
     * Email是否存在
     *
     * @param string $email
     * @return boolenn
     */
    public function is_email_exist($email) {
        return $this->db->where('email', $email)->count_all_results('user') > 0;
    }

    /**
     * Username是否存在
     *
     * @param string $username
     * @return boolenn
     */
    public function is_username_exist($username) {
        return $this->db->where('username', $username)->count_all_results('user') > 0;
    }

    /**
     * 是否允许注册 
	 * 检查同一IP重复注册
     * 规定时间内,同一IP将无法进行多次注册
	 *
	 * @param string $ip
     * @return boolenn
     */
    public function is_limit_register($ip) {
		$hour = 24;
		$user_register_limit = $this->db->get_where('user_register_limit', array('ip_address' => $ip))->row_array();
		if (!$user_register_limit || TIMESTAMP - $user_register_limit['last_regdate'] > $hour * 3600) {
			return false;
		} else {
			return true;
		}
    }

    /**
     * 生成盐值
     */
    public function salt() {
        return substr(md5(md5(uniqid())), 0, 6);
    }
}

/* End of file user_service.php */
/* Location: ./application/service/user/user_service.php */
